home *** CD-ROM | disk | FTP | other *** search
/ Programming an RTS Game with Direct3D / Programming an RTS Game with Direct3D.iso / Examples / Chapter 14 / Example 14.1 / particles.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2006-06-30  |  8.6 KB  |  302 lines

  1. #include "particles.h"
  2.  
  3. //Global Particle Textures
  4. IDirect3DTexture9* starTexture = NULL;
  5. IDirect3DTexture9* smokeTexture = NULL;
  6.  
  7. struct PARTICLE_VERTEX
  8. {
  9.     D3DXVECTOR3 position;
  10.     D3DCOLOR color;
  11.     static const DWORD FVF;
  12. };
  13.  
  14. const DWORD PARTICLE_VERTEX::FVF = D3DFVF_XYZ | D3DFVF_DIFFUSE;
  15.  
  16. int numParticles = 2048;
  17. IDirect3DVertexBuffer9* particleBuffer = NULL;
  18. DWORD bufferOffset = 0;
  19.  
  20. void LoadParticleResources(IDirect3DDevice9 *Dev)
  21. {
  22.     Dev->CreateVertexBuffer(numParticles * sizeof(PARTICLE_VERTEX), D3DUSAGE_DYNAMIC | D3DUSAGE_POINTS | D3DUSAGE_WRITEONLY,
  23.                             PARTICLE_VERTEX::FVF, D3DPOOL_DEFAULT, &particleBuffer, NULL);
  24.  
  25.     //Load textures
  26.     D3DXCreateTextureFromFile(Dev, "textures/star.dds", &starTexture);
  27.     D3DXCreateTextureFromFile(Dev, "textures/smoke.dds", &smokeTexture);
  28. }
  29.  
  30. void UnloadParticleResources()
  31. {
  32.     if(particleBuffer)
  33.         particleBuffer->Release();
  34.     particleBuffer = NULL;
  35.  
  36.     //Release textures
  37.     if(starTexture)starTexture->Release();
  38.     if(smokeTexture)smokeTexture->Release();
  39.  
  40.     starTexture = NULL;
  41.     smokeTexture = NULL;
  42. }
  43.  
  44. //////////////////////////////////////////////////////////////////////////////////////////////
  45. //                                PARTICLE_SYSTEM                                                //
  46. //////////////////////////////////////////////////////////////////////////////////////////////
  47.  
  48. PARTICLE_SYSTEM::PARTICLE_SYSTEM(IDirect3DDevice9 *Dev) : EFFECT(Dev)
  49. {
  50.     m_pTexture = NULL;
  51.     m_blendMode = D3DBLEND_ONE;
  52.     m_particleSize = 3.0f;
  53. }
  54.  
  55. PARTICLE_SYSTEM::~PARTICLE_SYSTEM()
  56. {
  57.     //Delete all particles
  58.     for(int i=0;i<m_particles.size();i++)
  59.         delete m_particles[i];
  60.     m_particles.clear();
  61. }
  62.  
  63. void PARTICLE_SYSTEM::Update(float timeDelta)
  64. {
  65.     
  66. }
  67.  
  68. void PARTICLE_SYSTEM::Render()
  69. {
  70.     if(m_particles.empty() || particleBuffer == NULL)return;
  71.  
  72.     PreRender();
  73.  
  74.     m_pDevice->SetTexture(0, m_pTexture);
  75.     m_pDevice->SetFVF(PARTICLE_VERTEX::FVF);
  76.     m_pDevice->SetStreamSource(0, particleBuffer, 0, sizeof(PARTICLE_VERTEX));
  77.  
  78.     int batchSize = 512;
  79.  
  80.     for(int i=0;i<m_particles.size();i+=batchSize)
  81.         RenderBatch(i, batchSize);
  82.  
  83.     PostRender();
  84. }
  85.  
  86. void PARTICLE_SYSTEM::RenderBatch(int start, int batchSize)
  87. {
  88.     //If we will reach the end of the vertex buffer, start over
  89.     if(bufferOffset + batchSize >= numParticles)bufferOffset = 0;
  90.  
  91.     //Lock the vertex buffer
  92.     PARTICLE_VERTEX *p = NULL;
  93.     particleBuffer->Lock(bufferOffset * sizeof(PARTICLE_VERTEX), 
  94.                          batchSize, (void**)&p, 
  95.                          bufferOffset ? D3DLOCK_NOOVERWRITE : D3DLOCK_DISCARD);
  96.  
  97.     int particlesRendered = 0;
  98.     for(int i=start;i<m_particles.size() && i < start + batchSize;i++)
  99.         if(!m_particles[i]->m_dead)
  100.         {
  101.             p->position = m_particles[i]->position;
  102.             p->color = m_particles[i]->color;
  103.             p++;
  104.             particlesRendered++;
  105.         }
  106.  
  107.     particleBuffer->Unlock();
  108.  
  109.     //Render batch 
  110.     if(particlesRendered > 0)
  111.         m_pDevice->DrawPrimitive(D3DPT_POINTLIST, bufferOffset, particlesRendered);
  112.  
  113.     //Increase offset
  114.     bufferOffset += batchSize;
  115. }
  116.  
  117. bool PARTICLE_SYSTEM::isDead()
  118. {
  119.     return true;
  120. }
  121.  
  122. void PARTICLE_SYSTEM::PreRender()
  123. {
  124.     m_pDevice->SetRenderState(D3DRS_POINTSPRITEENABLE, true);
  125.     m_pDevice->SetRenderState(D3DRS_POINTSCALEENABLE, true);
  126.     m_pDevice->SetRenderState(D3DRS_POINTSIZE, FtoDword(m_particleSize));
  127.     m_pDevice->SetRenderState(D3DRS_POINTSCALE_A, FtoDword(0.0f));
  128.     m_pDevice->SetRenderState(D3DRS_POINTSCALE_B, FtoDword(0.0f));
  129.     m_pDevice->SetRenderState(D3DRS_POINTSCALE_C, FtoDword(1.0f));
  130.     m_pDevice->SetRenderState(D3DRS_LIGHTING, false);
  131.  
  132.     m_pDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
  133.     m_pDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
  134.     m_pDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
  135.     m_pDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
  136.     m_pDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
  137.     m_pDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
  138.  
  139.     m_pDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, true);
  140.     m_pDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
  141.     m_pDevice->SetRenderState(D3DRS_DESTBLEND, m_blendMode);
  142.     m_pDevice->SetRenderState(D3DRS_ZWRITEENABLE, false);
  143.  
  144.     D3DXMATRIX identity;
  145.     D3DXMatrixIdentity(&identity);
  146.     m_pDevice->SetTransform(D3DTS_WORLD, &identity);
  147. }
  148.  
  149. void PARTICLE_SYSTEM::PostRender()
  150. {
  151.     m_pDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, false);
  152.     m_pDevice->SetRenderState(D3DRS_ZWRITEENABLE, true);
  153.  
  154.     m_pDevice->SetRenderState(D3DRS_POINTSPRITEENABLE, false);
  155.     m_pDevice->SetRenderState(D3DRS_POINTSCALEENABLE, false);
  156. }
  157.  
  158. //////////////////////////////////////////////////////////////////////////////////////////////
  159. //                                MAGIC SHOWER                                                //
  160. //////////////////////////////////////////////////////////////////////////////////////////////
  161.  
  162. MAGIC_SHOWER::MAGIC_SHOWER(IDirect3DDevice9 *Dev, int noParticles, D3DXVECTOR3 _origin) : PARTICLE_SYSTEM(Dev)
  163. {
  164.     m_origin = _origin;
  165.  
  166.     //Add initial m_particles
  167.     for(int i=0;i<noParticles;i++)
  168.     {
  169.         PARTICLE *p = new PARTICLE();
  170.         memset(p, 0, sizeof(PARTICLE));
  171.         p->time_to_live = rand()%5000 / 1000.0f;
  172.         p->color.a = 0.0f;
  173.         p->acceleration = D3DXVECTOR3(0.0f, -0.5f, 0.0f);
  174.         m_particles.push_back(p);
  175.     }
  176.  
  177.     m_pTexture = starTexture;
  178. }
  179.  
  180. void MAGIC_SHOWER::Update(float timeDelta)
  181. {
  182.     for(int i=0;i<m_particles.size();i++)
  183.     {
  184.         m_particles[i]->time_to_live -= timeDelta;
  185.         m_particles[i]->velocity += m_particles[i]->acceleration * timeDelta;    //Gravity
  186.         m_particles[i]->position += m_particles[i]->velocity * timeDelta;
  187.         m_particles[i]->color.a = m_particles[i]->time_to_live / 5.0f;
  188.  
  189.         if(m_particles[i]->time_to_live <= 0.0f)    //Re-spawn
  190.         {
  191.             m_particles[i]->position = m_origin;
  192.             
  193.             m_particles[i]->velocity = D3DXVECTOR3((rand()%2000 / 1000.0f) - 1.0f,
  194.                                                  (rand()%2000 / 1000.0f) - 1.0f,
  195.                                                  (rand()%2000 / 1000.0f) - 1.0f);
  196.  
  197.             D3DXVec3Normalize(&m_particles[i]->velocity, &m_particles[i]->velocity);
  198.             m_particles[i]->velocity *= 2.0f;
  199.  
  200.             m_particles[i]->color = D3DXCOLOR(rand()%1000 / 1000.0f, rand()%1000 / 1000.0f, rand()%1000 / 1000.0f, 1.0f);
  201.  
  202.             m_particles[i]->time_to_live = rand()%4000 / 1000.0f + 1.0f;
  203.         }
  204.     }
  205. }
  206.  
  207. bool MAGIC_SHOWER::isDead()
  208. {
  209.     return false;
  210. }
  211.  
  212. //////////////////////////////////////////////////////////////////////////////////////////////
  213. //                                SMOKE                                                        //
  214. //////////////////////////////////////////////////////////////////////////////////////////////
  215.  
  216. SMOKE::SMOKE(IDirect3DDevice9 *Dev, int noParticles, D3DXVECTOR3 _origin) : PARTICLE_SYSTEM(Dev)
  217. {
  218.     m_origin = _origin;
  219.     m_numAlive = 1;
  220.  
  221.     //Add initial particles
  222.     for(int i=0;i<noParticles;i++)
  223.     {
  224.         PARTICLE *p = new PARTICLE();
  225.         memset(p, 0, sizeof(PARTICLE));
  226.         p->time_to_live = rand()%5000 / 1000.0f;
  227.         p->m_dead = true;
  228.         p->acceleration = D3DXVECTOR3(-0.07f, 0.05f, 0.02f);        //Sideways wind
  229.         m_particles.push_back(p);
  230.     }
  231.  
  232.     m_dead = false;
  233.     m_blendMode = D3DBLEND_INVSRCALPHA;
  234.     m_particleSize = 4.0f;
  235.     m_pTexture = smokeTexture;
  236. }
  237.  
  238. void SMOKE::Update(float timeDelta)
  239. {
  240.     m_numAlive = 0;
  241.  
  242.     for(int i=0;i<m_particles.size();i++)
  243.     {
  244.         if(!m_particles[i]->m_dead)
  245.         {
  246.             m_particles[i]->time_to_live -= timeDelta;
  247.             m_particles[i]->velocity += m_particles[i]->acceleration * timeDelta;    //Wind
  248.             m_particles[i]->position += m_particles[i]->velocity * timeDelta;
  249.             m_numAlive++;
  250.             float aim = m_particles[i]->time_to_live * 0.1f;
  251.  
  252.             if(m_particles[i]->time_to_live <= 0.0f)    //Re-spawn
  253.             {
  254.                 m_particles[i]->color.a -= timeDelta * 0.05f;
  255.  
  256.                 if(m_particles[i]->color.a <= 0.0f)
  257.                 {
  258.                     m_particles[i]->color.a = 0.0f;
  259.                     m_particles[i]->m_dead = true;
  260.                 }
  261.             }
  262.             else if(m_particles[i]->color.a < aim)
  263.                 m_particles[i]->color.a += timeDelta * 0.015f;
  264.         }
  265.  
  266.         if(m_particles[i]->m_dead && !m_dead)
  267.         {
  268.             //Random start position
  269.             D3DXVECTOR3 p = D3DXVECTOR3((rand()%2000 / 1000.0f) - 1.0f,
  270.                                         (rand()%2000 / 1000.0f) - 1.0f,
  271.                                         (rand()%2000 / 1000.0f) - 1.0f);
  272.             p *= 0.5f;
  273.             p.y -= (rand()%200) / 1000.0f;
  274.  
  275.             m_particles[i]->position = m_origin + p;        
  276.  
  277.             //Circular direction
  278.             float angle = (rand()%6280) / 1000.0f;
  279.             float spread = ((rand()%1000) / 1000.0f) * 0.4f;
  280.  
  281.             m_particles[i]->velocity = D3DXVECTOR3(cos(angle) * spread,
  282.                                                  1.0f + ((rand()%2000 / 1000.0f) - 1.0f) * 0.5f,
  283.                                                  sin(angle) * spread);
  284.  
  285.             D3DXVec3Normalize(&m_particles[i]->velocity, &m_particles[i]->velocity);
  286.             m_particles[i]->velocity *= 0.5f;
  287.  
  288.             //Random graydscale color
  289.             float c = rand()%900 / 1000.0f + 0.1f;
  290.             m_particles[i]->color = D3DXCOLOR(c, c, c, 0.01f);
  291.  
  292.             m_particles[i]->time_to_live = rand()%6000 / 1000.0f + 1.0f;
  293.  
  294.             m_particles[i]->m_dead = false;
  295.         }
  296.     }
  297. }
  298.  
  299. bool SMOKE::isDead()
  300. {
  301.     return m_numAlive > 0;
  302. }